﻿using Devil;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

namespace GameToolkit
{
    public delegate void ChangeDataCallback<T>(T from, T to);

    public partial class ActorBehaviour : SharingConfigMono<ActorBehaviourConfig>, ICullingUpdate
    {
        //#region events
        //public event System.Action<IFeature> OnRegisted;
        //public event System.Action<IFeature> OnUnregisted;
        //public event ChangeDataCallback<IController> OnResetController;
        //#endregion

        //[SerializeField]
        //ECullDistance m_UpdateDistance = ECullDistance.NearBy;

        //[SerializeField]
        //ECullingUpdateMode m_UpdateModes = ECullingUpdateMode.Update | ECullingUpdateMode.Background;

        [SerializeField]
        ActorFeatureDescriptor[] m_Features;

        #region enumerable

        public T FindFeature<T>(FilterDelegate<IFeature> where = null) where T : class, IFeature
        {
            if (mAllFeatures == null)
                return null;
            T feature = null;
            ExecuteLater();
            try
            {
                foreach (var f in mAllFeatures)
                {
                    if (f is T t && (where == null || where(t)))
                    {
                        feature = t;
                        break;
                    }
                }
            }
            catch (System.Exception e)
            {
                Debug.LogException(e);
            }
            finally
            {
                ExecuteImmediate();
            }
            return feature;
        }

        public void GetAllFeatures<T>(ICollection<T> features, FilterDelegate<T> where = null) where T : class, IFeature
        {
            if (features == null || mAllFeatures == null)
                return;
            ExecuteLater();
            try
            {
                foreach (var f in mAllFeatures)
                {
                    if (f is T t && (where == null || where(t)))
                    {
                        features.Add(t);
                    }
                }
            }
            catch (System.Exception e)
            {
                Debug.LogException(e);
            }
            finally
            {
                ExecuteImmediate();
            }
        }

        #endregion

        #region culling update

        ECullingUpdateMode mUpdateMode;
        int ICullingUpdate.CulledUpdateDistanceLv => (int)ECullDistance.Infinite;

        int ICullingUpdate.AlwaysUpdateDistanceLv => Config == null ? 1 : (int)Config.UpdateDistance;

        ECullingUpdateMode ICullingUpdate.UpdateMode => Config == null ? (ECullingUpdateMode.Update | ECullingUpdateMode.Background) : Config.UpdateModes;
        public ECullingUpdateMode CurrentUpdateMode => mUpdateMode;

        void ICullingUpdate.OnCullingUpdate(CullingCamera culler, ECullingUpdateMode mode)
        {
            if (!mIsActive)
                return;
            var deltaTime = culler.deltaTime;
            mUpdateMode = mode;
            CompleteCmdBuffer(false);
            ExecuteLater();
            try
            {
                // update cd
                for (int i = mCDTicks.Count - 1; i >= 0; i--)
                {
                    var cd = mCDTicks[i];
                    cd.OnCDTick(deltaTime);
                    if (cd.Progress <= 0)
                        mCDTicks.RemoveAt(i);
                }
                // update controller
                if (mCurrentController != null)
                {
                    mCurrentController.OnControlling(deltaTime);
                }
                // execute input
                mInputResponse.Clear();
                for (int i = 0; i < mInputGroups.Count; i++)
                {
                    var input = mInputGroups[i];
                    if (input.UseAction())
                    {
                        for (int k = input.Count - 1; k >= 0; k--)
                        {
                            var ability = input[k];
                            mInputResponse.Add(new AbilityWithInput(ability == mBaseAbility || ability == mAdditionalAbility, ability, input));
                        }
                    }
                }
                IAbility currentBase = mBaseAbility;
                IAbility currentAdd = mAdditionalAbility;
                bool evaluateBase = false;
                bool evaluateAdd = false;
                while (mInputResponse.Count > 0)
                {
                    var response = mInputResponse.RemoveTop();
                    // 输入不可用
                    if (!response.input.mIsUsable)
                        continue;
                    // 避免重复赋值
                    if (response.isAdditional ? evaluateAdd : evaluateBase)
                        continue;
                    // 不能被打断
                    if (response.isAdditional && currentAdd != null && currentAdd != response.ability && !currentAdd.IsInterruptable(response.ability))
                        continue;
                    if (response.ability is IOverriderAbility && currentBase != null && !currentBase.IsInterruptable(response.ability))
                        continue;
                    if (!response.isAdditional && currentBase != null && currentBase != response.ability && !currentBase.IsInterruptable(response.ability))
                        continue;
                    // 执行输入
                    if (response.ability.ExecuteInput(response.input))
                    {
                        response.input.mIsUsable = false;
                        if (response.isAdditional)
                        {
                            evaluateAdd = true;
                            currentAdd = response.ability;
                            if (currentAdd is IOverriderAbility)
                            {
                                evaluateBase = true;
                                currentBase = null;
                            }
                        }
                        else
                        {
                            evaluateBase = true;
                            currentBase = response.ability;
                        }
                    }
                    if (evaluateBase && evaluateAdd)
                        break;
                    if (!response.isAdditional && currentAdd is IOverriderAbility)
                        break;
                }
                //BaseAbility = currentBase;
                //AdditionalAbility = currentAdd;
                UpdateAbilityState(currentBase, currentAdd, true);
                //// execute actor update
                var updateBase = currentBase != null && currentBase.OnUpdateAbility(deltaTime);
                var updateAdd = currentAdd != null && currentAdd.OnUpdateAbility(deltaTime);
                if (!updateAdd)
                {
                    currentAdd = null;
                }
                if (!updateBase)
                {
                    currentBase = null;
                }
                UpdateAbilityState(currentBase, currentAdd, true);
                if (mCurrentPoseture != null)
                    mCurrentPoseture.OnUpdatePoseture(deltaTime);
            }
            catch (System.Exception e)
            {
                Debug.LogException(e);
            }
            finally
            {
                ExecuteImmediate();
            }
            CompleteCmdBuffer(false);
        }

        #endregion

        #region execution buffer

        enum ECmdAction : byte
        {
            Regist,
            Unregist,
            Activate,
            ForceActivate,
        }

        struct CmdBuffer
        {
            public IFeature feature;
            public ECmdAction action;
            public CmdBuffer(IFeature feature, ECmdAction action)
            {
                this.feature = feature;
                this.action = action;
            }

            public void Execute(ActorBehaviour actor)
            {
                switch (this.action)
                {
                    case ECmdAction.Regist:
                        actor.ExecuteRegist(feature);
                        break;
                    case ECmdAction.Unregist:
                        actor.ExecuteUnregist(feature);
                        break;
                    case ECmdAction.Activate:
                        actor.ExecuteActivate(feature as IAbility, false);
                        break;
                    case ECmdAction.ForceActivate:
                        actor.ExecuteActivate(feature as IAbility, true);
                        break;
                    default:
                        break;
                }
            }
        }

        // 注册命令缓存，防止在某些功能执行时，不能执行注册/注销操作，将注册指定缓存带后续执行
        protected readonly object _sync_lock = new object();
        readonly Queue<CmdBuffer> mExecutionBuffer = new Queue<CmdBuffer>(4);
        int mExecLater;
        bool mRebindInput;

        bool ShouldExecuteLater()
        {
            return mExecLater > 0 || !ParallelUnity.IsMainThread;
        }

        void ExecuteLater()
        {
            Interlocked.Increment(ref mExecLater);
            //lock (_sync_lock)
            //{
            //    mExecLater++;
            //}
        }

        void ExecuteImmediate()
        {
            Interlocked.Decrement(ref mExecLater);
            //lock (_sync_lock)
            //{
            //    mExecLater--;
            //}
        }

        InputGroup GetInputGroup(Object descriptor)
        {
            for (int i = 0; i < mInputGroups.Count; i++)
            {
                var grp = mInputGroups[i];
                if (grp.Descriptor == descriptor)
                    return grp;
            }
            return null;
        }

        void GetAbilityInputs(ICollection<Object> descriptorCache)
        {
            foreach(var feature in mAllFeatures)
            {
                var ability = feature as IAbilityWithInput;
                if (ability == null)
                    continue;
                descriptorCache.Clear();
                ability.GetUsedInputs(descriptorCache);
                foreach (var key in descriptorCache)
                {
                    var grp = GetInputGroup(key);
                    if (grp == null)
                    {
                        var input = mCurrentController.GetInputAction(key);
                        if (input != null)
                        {
                            grp = new InputGroup(key, input);
                            mInputGroups.Add(grp);
                        }
                    }
                    if (grp != null)
                        grp.mAbilities.Add(ability);
                }
            }
        }

        // 完成命令缓存
        void CompleteCmdBuffer(bool cleanup)
        {
            lock (_sync_lock)
            {
                if (mExecLater == 0)
                {
                    while (mExecutionBuffer.Count > 0)
                    {
                        var reg = mExecutionBuffer.Dequeue();
                        reg.Execute(this);
                    }
                    if (mRebindInput || cleanup)
                    {
                        mRebindInput = false;
                        var ctrl = mCurrentController;
                        // bind input
                        mCurrentController = cleanup || mControllers.Count == 0 ? null : mControllers.TopValule;
                        var size = mInputGroups.Count;
                        for (int i = 0; i < size; i++)
                        {
                            var grp = mInputGroups[i];
                            grp.mAbilities.Clear();
                        }
                        if (mCurrentController != null)
                        {
                            var descriptors = new HashSet<Object>();
                            GetAbilityInputs(descriptors);
                        }
                        // clean unused inputs
                        for (int i = size - 1; i >= 0; i--)
                        {
                            var grp = mInputGroups[i];
                            if (grp.mAbilities.Count == 0)
                            {
                                mInputGroups.RemoveAt(i);
                            }
                        }
                        if(ctrl != mCurrentController)
                        {
                            if (ctrl != null)
                                ctrl.OnDeactivate();
                            if (mCurrentController != null)
                                mCurrentController.OnActivate();
                        }
                    }
                }
            }
        }

        #endregion

        #region monobehaviour

        // initialize data
        bool mIsInitialized;
        bool mIsActive;
        Animator mAnimator;

        protected virtual void Awake()
        {
            mAnimator = GetComponent<Animator>();
        }

        // don't override OnEnable + OnDisable, replace by OnActorEnable + OnActorDisable
        private void OnEnable()
        {
            InitDefaultFeatures();
            if (!mIsActive)
            {
                mIsActive = true;
                mRebindInput = true;
                ExecuteLater();
                try
                {
                    OnActorEnable();
                }
                catch (System.Exception e)
                {
                    Debug.LogException(e);
                }
                finally
                {
                    ExecuteImmediate();
                }
                CompleteCmdBuffer(false);
            }
        }

        private void OnDisable()
        {
            if (mIsActive)
            {
                mIsActive = false;
                ExecuteLater();
                try
                {
                    OnActorDisable();
                }
                catch (System.Exception e)
                {
                    Debug.LogException(e);
                }
                finally
                {
                    ExecuteImmediate();
                }
                CompleteCmdBuffer(true);
            }
        }

        protected virtual void OnDestroy()
        {
            
        }

        #endregion

        #region behaviour logic

        struct AbilityWithInput
        {
            internal bool isAdditional;
            internal bool isCurrent;
            internal IAbilityWithInput ability;
            internal InputGroup input;
            internal AbilityWithInput(bool isCurrent, IAbilityWithInput ability, InputGroup input)
            {
                this.isCurrent = isCurrent;
                this.ability = ability;
                this.input = input;
                this.isAdditional = ability is IOverriderAbility || ability is IAdditionalAbility;
            }

            internal static int ComparePriority(AbilityWithInput a, AbilityWithInput b)
            {
                if(a.isCurrent != b.isCurrent)
                    return a.isCurrent ? 1 : -1;
                if(a.isAdditional != b.isAdditional)
                    return a.isAdditional ? 1 : -1;
                var p1 = a.ability.Priority;
                var p2 = b.ability.Priority;
                if (p1 != p2)
                    return p1 > p2 ? 1 : -1;
                return 0;
            }
        }

        class InputGroup : IAbilityInput
        {
            Object mDescriptor;
            IInputAction mAction;
            // 优先级由低到高
            internal readonly List<IAbilityWithInput> mAbilities;
            bool mIsDown;
            bool mIsUp;
            bool mIsHolding;

            internal bool mIsUsable;
            internal int Count => mAbilities.Count;
            internal IAbilityWithInput this[int index] => mAbilities[index];

            public Object Descriptor => mDescriptor;
            public bool IsDown => mIsDown;
            public bool IsUp => mIsUp;
            public bool IsHolding => mIsHolding;
            public IInputAction Action => mAction;

            public bool GetValue<T>(out T value)
            {
                if(mAction is IInputAction<T> input)
                {
                    value = input.GetInputValue();
                    return true;
                }
                else
                {
                    value = default;
                    return false;
                }
            }

            internal InputGroup(Object descriptor, IInputAction action)
            {
                mAction = action;
                mDescriptor = descriptor;
                mAbilities = new List<IAbilityWithInput>();
            }

            internal bool UseAction()
            {
                var hold = mAction != null && mAction.IsHolding;
                mIsDown = hold && !mIsHolding;
                mIsUp = !hold && mIsHolding;
                mIsHolding = hold;
                mIsUsable = mIsDown || mIsUp || mIsHolding;
                return mIsUsable;
            }

            internal void GetCurrenetAbilityIndex(ActorBehaviour actor, out int baseIndex, out int overlayIndex)
            {
                baseIndex = -1;
                overlayIndex = -1;
                var found = 0;
                if (actor.mBaseAbility == null)
                    found++;
                if (actor.mAdditionalAbility == null)
                    found++;
                for (int i = 0; found < 2 && i < mAbilities.Count; i++)
                {
                    var ab = mAbilities[i];
                    if (ab == actor.mBaseAbility)
                    {
                        baseIndex = i;
                        found++;
                    }
                    else if (ab == actor.mAdditionalAbility)
                    {
                        overlayIndex = -1;
                        found++;
                    }
                }
            }
        }

        IDefaultPoseture mDefaultPoseture;
        HashSet<IFeature> mAllFeatures;
        // 同时只能激活一个控制器（优先级最大的控制器）
        MinHeap<IController> mControllers;
        RandomList<IAbilityWithCD> mCDTicks;
        RandomList<InputGroup> mInputGroups;
        MinHeap<AbilityWithInput> mInputResponse;

        // runtime datas
        IController mCurrentController;
        IPoseture mCurrentPoseture;
        IAbility mBaseAbility;
        IAbility mAdditionalAbility;

        // 当前姿态
        public EPosture CurrentPoseture => mCurrentPoseture == null ? EPosture.Standing : mCurrentPoseture.PosetureState;
        public Vector3 CurrentVelocity => mCurrentPoseture == null ? Vector3.zero : mCurrentPoseture.Velocity;
        public IController CurrentController => mCurrentController;
        public IPoseture Poseture
        {
            get { return mCurrentPoseture; }
            private set
            {
                if (mCurrentPoseture != value)
                {
                    var old = mCurrentPoseture;
                    mCurrentPoseture = value;
                    ExecuteLater();
                    try
                    {
                        Vector3 v;
                        EPosture pose;
                        if (old != null)
                        {
                            v = old.Velocity;
                            pose = old.PosetureState;
                            old.OnExit();
                        }
                        else
                        {
                            v = Vector3.zero;
                            pose = EPosture.Standing;
                        }
                        if (mCurrentPoseture != null)
                            mCurrentPoseture.OnEnter(v, pose);
                    }
                    catch (System.Exception e)
                    {
                        Debug.LogException(e);
                    }
                    finally
                    {
                        ExecuteImmediate();
                    }
                }
            }
        }

        // 当前基础能力
        public IAbility BaseAbility
        {
            get { return mBaseAbility; }
            private set
            {
                if (mBaseAbility != value)
                {
                    var old = mBaseAbility;
                    mBaseAbility = value;
                    ExecuteLater();
                    try
                    {
                        if (old != null)
                        {
                            old.OnDeactivate();
                            if (old is IAbilityWithCD cd && cd.Progress > 0 && !mCDTicks.Contains(cd))
                                mCDTicks.Add(cd);
                        }
                        if (mBaseAbility != null)
                        {
                            mBaseAbility.OnActivate();
                        }
                    }
                    catch (System.Exception e)
                    {
                        Debug.LogException(e);
                    }
                    finally
                    {
                        ExecuteImmediate();
                    }
                }
            }
        }

        // 当前进阶能力
        public IAbility AdditionalAbility
        {
            get { return mAdditionalAbility; }
            private set
            {
                if (mAdditionalAbility != value)
                {
                    var old = mAdditionalAbility;
                    mAdditionalAbility = value;
                    ExecuteLater();
                    try
                    {
                        if (old != null)
                        {
                            old.OnDeactivate();
                            if (old is IAbilityWithCD cd && cd.Progress > 0 && !mCDTicks.Contains(cd))
                                mCDTicks.Add(cd);
                        }
                        if (mAdditionalAbility != null)
                        {
                            mAdditionalAbility.OnActivate();
                        }
                    }
                    catch (System.Exception e)
                    {
                        Debug.LogException(e);
                    }
                    finally
                    {
                        ExecuteImmediate();
                    }
                }
            }
        }

        public bool HasParameter(AnimParam arg)
        {
            if (mAnimator != null)
            {
                var num = mAnimator.parameterCount;
                for (int i = 0; i < num; i++)
                {
                    var p = mAnimator.GetParameter(i);
                    if (p.nameHash == arg.id && p.type == arg.type)
                        return true;
                }
            }
            return false;
        }

        void UpdateAbilityState(IAbility baseAbility, IAbility additionalAbility, bool updatePose)
        {
            var pose = mCurrentPoseture;
            var currentBase = mBaseAbility;
            var currentAdd = mAdditionalAbility;
            mBaseAbility = baseAbility;
            mAdditionalAbility = additionalAbility;
            if(updatePose)
            {
                if (additionalAbility is IPoseture pose1)
                    mCurrentPoseture = pose1;
                else if (baseAbility is IPoseture pose2)
                    mCurrentPoseture = pose2;
                else
                    mCurrentPoseture = mDefaultPoseture;
            }
            var newpose = pose != mCurrentPoseture;
            var newbase = currentBase != mBaseAbility;
            var newadd = currentAdd != mAdditionalAbility;
            if(newpose || newbase || newadd)
            {
                Vector3 v;
                EPosture poseture;
                if (newadd && currentAdd != null)
                    currentAdd.OnDeactivate();
                if (newbase && currentBase != null)
                    currentBase.OnDeactivate();
                if (newpose && pose != null)
                {
                    v = pose.Velocity;
                    poseture = pose.PosetureState;
                    pose.OnExit();
                }
                else
                {
                    v = Vector3.zero;
                    poseture = EPosture.Standing;
                }
                if (newpose && mCurrentPoseture != null)
                    mCurrentPoseture.OnEnter(v, poseture);
                if (newbase && mBaseAbility != null)
                    mBaseAbility.OnActivate();
                if (newadd && mAdditionalAbility != null)
                    mAdditionalAbility.OnActivate();
            }
        }

        // 初始化默认 feature (绑定在 gameObject 上的组件)
        void InitDefaultFeatures()
        {
            lock (_sync_lock)
            {
                if (mIsInitialized)
                    return;
                mIsInitialized = true;
            }
            ExecuteLater();
            try
            {
                mRebindInput = true;
                mAllFeatures = new HashSet<IFeature>();
                mControllers = new MinHeap<IController>(4, (ctrl) => -ctrl.Priority);
                mCDTicks = new RandomList<IAbilityWithCD>(4, (a, b) => a == b, true);
                mInputGroups = new RandomList<InputGroup>(8, (a, b) => a == b, true);
                mInputResponse = new MinHeap<AbilityWithInput>(8, (a, b) => AbilityWithInput.ComparePriority(b, a));
                mDefaultPoseture = null;
                var lst = CacheUtil.GetListCahce<IFeature>();
                GetComponents(lst);
                var len = m_Features == null ? 0 : m_Features.Length;
                for (int i = 0; i < len; i++)
                {
                    var feature = m_Features[i] == null ? null : m_Features[i].Creaet();
                    if (feature != null)
                        lst.Add(feature);
                }
                for (int i = 0; i < lst.Count; i++)
                {
                    var feature = lst[i];
                    if (!ExecuteRegist(feature))
                        continue;
                    if (feature is IDefaultPoseture pose)
                    {
                        if (mDefaultPoseture == null || mDefaultPoseture.ExecutionOrder > pose.ExecutionOrder)
                        {
                            mDefaultPoseture = pose;
                        }
                    }
                }
            }
            catch (System.Exception e)
            {
                Debug.LogException(e);
            }
            finally
            {
                ExecuteImmediate();
            }
        }

        // 替换 OnEnable, 该方法会保证在对象绑定的所有组件的 OnEnable 执行之后执行
        protected virtual void OnActorEnable()
        {
            mCDTicks.Clear();
            foreach(var feature in mAllFeatures)
            {
                EnableFeature(feature);
            }
            IPoseture pose;
            if (mAdditionalAbility is IPoseture pose1)
                pose = pose1;
            else if (mBaseAbility is IPoseture pose2)
                pose = pose2;
            else
                pose = mDefaultPoseture;
            Poseture = pose;
        }

        // 替代 OnDisable
        protected virtual void OnActorDisable()
        {
            mCDTicks.Clear();
            Poseture = null;
            BaseAbility = null;
            AdditionalAbility = null;
            if(mCurrentController != null)
            {
                mCurrentController.OnDeactivate();
                mCurrentController = null;
            }
            foreach(var feature in mAllFeatures)
            {
                DisableFeature(feature);
            }
        }

        void EnableFeature(IFeature feature)
        {
            feature.OnFeatureEnable(this);
            if(feature is IAbilityWithCD cd && cd.Progress > 0 && !mCDTicks.Contains(cd))
            {
                mCDTicks.Add(cd);
            }
        }

        void DisableFeature(IFeature feature)
        {
            if (feature is IAbilityWithCD cd)
                mCDTicks.Remove(cd);
            if (feature == mBaseAbility)
                BaseAbility = null;
            else if (feature == mAdditionalAbility)
                AdditionalAbility = null;
            feature.OnFeatureDisable(this);
        }

        // on main thread
        bool ExecuteRegist(IFeature feature)
        {
            if (mAllFeatures == null || !mAllFeatures.Add(feature))
                return false;
            if (feature is IController ctrl)
            {
                var current = mControllers.Count > 0 ? mControllers.TopValule : null;
                mControllers.Add(ctrl);
                var next = mControllers.TopValule;
                mRebindInput |= current != next;
            }
            else
            {
                mRebindInput |= feature is IAbilityWithInput;
            }
            if (mIsActive)
            {
                EnableFeature(feature);
            }
            return true;
        }

        // on main thread
        bool ExecuteUnregist(IFeature feature)
        {
            if (mAllFeatures == null || !mAllFeatures.Remove(feature))
                return false;
            if (mIsActive)
            {
                DisableFeature(feature);
            }
            if (feature is IAbility abi)
            {
                mRebindInput |= feature is IAbilityWithInput;
            }
            else if (feature is IController ctrl)
            {
                mControllers.Remove(ctrl);
                mRebindInput = true;
            }
            if (feature == mDefaultPoseture)
            {
                mDefaultPoseture = null;
            }
            return true;
        }

        // on main thread
        bool ExecuteActivate(IAbility ability, bool forceActivate)
        {
            if (mAllFeatures == null || !mAllFeatures.Contains(ability))
                return false;
            if (!forceActivate)
            {
                var isOverrider = ability is IOverriderAbility;
                var isAdditional = isOverrider || (ability is IAdditionalAbility);
                // 中断执行？
                if (isAdditional && mAdditionalAbility != null && !mAdditionalAbility.IsInterruptable(ability))
                    return false;
                if ((!isAdditional || isOverrider) && mBaseAbility != null && !mBaseAbility.IsInterruptable(ability))
                    return false;
            }
            var baseAb = mBaseAbility;
            var addAb = mAdditionalAbility;
            if (ability is IOverriderAbility)
            {
                addAb = ability;
                baseAb = null;
            }
            else if(ability is IAdditionalAbility)
            {
                addAb = ability;
            }
            else
            {
                baseAb = ability;
            }
            UpdateAbilityState(baseAb, addAb, true);
            return true;
        }

        // no thread limitition
        public void Regist(IFeature feature)
        {
            if (feature == null)
                return;
            lock (_sync_lock)
            {
                if (ShouldExecuteLater())
                {
                    var reg = new CmdBuffer(feature, ECmdAction.Regist);
                    mExecutionBuffer.Enqueue(reg);
                    return;
                }
            }
            InitDefaultFeatures();
            ExecuteRegist(feature);
        }

        // no thread limitition
        public void Unregist(IFeature feature)
        {
            if (feature == null)
                return;
            lock (_sync_lock)
            {
                if (ShouldExecuteLater())
                {
                    var reg = new CmdBuffer(feature, ECmdAction.Unregist);
                    mExecutionBuffer.Enqueue(reg);
                    return;
                }
            }
            ExecuteUnregist(feature);
        }

        // no thread limitition 
        public void Activate(IAbility ability, bool forceActivate = false)
        {
            if (ability == null)
                return;
            lock (_sync_lock)
            {
                if (ShouldExecuteLater())
                {
                    var cmd = new CmdBuffer(ability, forceActivate ? ECmdAction.ForceActivate : ECmdAction.Activate);
                    mExecutionBuffer.Enqueue(cmd);
                    return;
                }
            }
            ExecuteActivate(ability, forceActivate);
        }

        #endregion

    }
}
